package com.mvvm.start.base.utils

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.viewbinding.ViewBinding
import com.alibaba.android.arouter.launcher.ARouter
import com.google.gson.Gson
import com.mvvm.start.base.BaseApplication
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.lang.reflect.ParameterizedType


/**
 * @author
 * @功能: 扩展函数的工具类
 * @Creat 2020/11/6 5:55 PM
 * @Compony 465008238@qq.com
 */


/**
 * 处理控件多次点击的情况
 * 两次点击按钮之间的点击间隔不能少于1000毫秒
 */
val MIN_CLICK_DELAY_TIME: Int = 1000
var lastClickTime: Long = 0
fun isFastClick(block: () -> Unit): Boolean {
    var flag = false
    val curClickTime = System.currentTimeMillis()
    if (curClickTime - lastClickTime >= MIN_CLICK_DELAY_TIME) {
        flag = true
    }
    lastClickTime = curClickTime
    if (flag) {
        block()
    }
    return flag
}


fun Any?.toNullString(): String {
    return this?.toString() ?: "null"
}



var gson: Gson? = null
fun Any.toJson(): String {
    return if (isNull(gson)) {
        gson = Gson()
        gson?.toJson(this) as String

    } else {
        gson?.toJson(this) as String
    }
}

/**
 * 吐司扩展函数
 *
 * @param gravity Toast的显示位置
 * @param x Toast的显示位置 X轴的偏移量
 * @param y Toast的显示位置 Y轴的偏移量
 */
var toasts: Toast? = null
fun toast(msg: Any, duration: Int = Toast.LENGTH_LONG, block: Toast.() -> Unit) {
    if (isNull(toasts)) {
        toasts = Toast.makeText(BaseApplication.context, msg.toString(), duration)
    }
    toasts?.block()
    toasts?.cancel()
    toasts?.show()
}

fun Any.toast(gravity: Int = Gravity.BOTTOM, x: Int = 0, y: Int = 100) {
    if (!isNull(toasts)) {
        toasts?.cancel()
    }
    toasts = Toast.makeText(BaseApplication.context, this.toString(), Toast.LENGTH_LONG).apply {
        setGravity(gravity, x, y)
    }
    toasts?.show()
}


/**
 * 通过泛型进行封装
 * java规定所有类型的数字都是可比较的  需要实现Comparabla接口
 */
fun <T : Comparable<T>> max(vararg nums: T): T {
    if (nums.isNullOrEmpty()) throw RuntimeException("parms can not be empty")
    var maxNum = nums[0]
    for (num in nums) {
        if (num > maxNum) maxNum = num
    }
    return maxNum
}

/**
 * 启动一个Service 解决startService中 onStartCommand重复调用问题
 *
 * @param intentBlock Intent携带参数的回调
 * @param startBlock Service启动的回调
 * @param runBlock Service正在运行中的回调
 */
inline fun <reified T> ktstartService(
    intentBlock: Intent.() -> Unit,
    startBlock: () -> Unit,
    runBlock: () -> Unit
) {
    if (ServiceUtils.isServiceRunning(BaseApplication.context, T::class.java.name)) {
        runBlock()
        return
    }
    startBlock()
    BaseApplication.context.startService(ktgetIntent<T>(BaseApplication.context) {
        intentBlock()
    })
    runBlock()
}

/**
 * 启动一个Service 如果正在Service正在运行 直接return
 */
inline fun <reified T> ktstartService() {
    if (ServiceUtils.isServiceRunning(BaseApplication.context, T::class.java.name)) {
        return
    }
    BaseApplication.context.startService(ktgetIntent<T>(BaseApplication.context))
    "${T::class.java.name}".loge("服务启动成功")
}

/**
 * 停止一个Service 如果正在Service不正在运行 直接return
 */
inline fun <reified T> ktstopService() {
    if (!ServiceUtils.isServiceRunning(BaseApplication.context, T::class.java.name)) {
        return
    }
    BaseApplication.context.stopService(ktgetIntent<T>(BaseApplication.context))
    "${T::class.java.name}".loge("服务关闭成功")
}


/****************************************Activity跳转的扩展函数****************************************************/

/**
 * Activity跳转
 * startActivitys<T>()
 * 不携带参数的封装
 *
 * @param context 上下文
 */
inline fun <reified T> ktstartActivity(context: Context? = BaseApplication.context) {
    context?.startActivity(ktgetIntent<T>(BaseApplication.context).apply {
        if (context == BaseApplication.context) {
            //兼容非Activity启动Activity造成的闪退问题
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
        }
    })
}

/**
 * Activity跳转 携带参数的跳转
 * reified 这个是为了满足inline特性而设计的语法糖，因为给函数使用内联之后，
 * 编译器会用其函数体来替换掉函数调用，而如果该函数里面有泛型就可能会出现编译器不懂该泛型的问题，
 * 所以引入reified，使该泛型被智能替换成对应的类型
 * @param context 上下文
 * @param block intent填写参数的回调
 */
inline fun <reified T> ktstartActivity(
    context: Context? = BaseApplication.context,
    block: Intent.() -> Unit
) {
    context?.startActivity(ktgetIntent<T>(BaseApplication.context) {
        block()
    }.apply {
        if (context == BaseApplication.context) {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
        }
    })
}

/**
 * 获取一个Intent 对象并携带参数的封装
 *
 * @param context 上下文
 * @param block intent填写参数的回调
 */
inline fun <reified T> ktgetIntent(context: Context, block: Intent.() -> Unit): Intent =
    Intent(context, T::class.java).apply {
        block()
    }

/**
 * 获取一个Intent 对象的封装
 *
 * @param context 上下文
 */
inline fun <reified T> ktgetIntent(context: Context): Intent = Intent(context, T::class.java)

/**
 * 携带参数带有返回值的Activity跳转
 * @param activity 上下文
 * @param code 请求返回的code码
 * @param block intent填写参数的回调
 */
inline fun <reified T> ktstartForResultActivity(
    activity: Activity,
    code: Int,
    block: Intent.() -> Unit
) {
    activity.startActivityForResult(ktgetIntent<T>(activity) {
        block()
    }, code)
}

/**
 * 带有返回值的Activity跳转
 *
 * @param activity 上下文
 * @param code 请求返回的code码
 */
inline fun <reified T> ktstartForResultActivity(
    activity: Activity,
    code: Int
) {
    activity.startActivityForResult(ktgetIntent<T>(activity), code)
}

/**
 * 批量设置控件点击事件。
 *
 * @param v 点击的控件
 * @param block 处理点击事件回调代码块
 */
inline fun ktsetOnClickListener(vararg v: View?, crossinline block: View.() -> Unit) {
    val listener = View.OnClickListener { it.block() }
    v.forEach { it?.setOnClickListener(listener) }
}


/**
 *初始化ViewModel的封装
 */
inline fun <reified T : ViewModel> initViewModel(
    context: ViewModelStoreOwner,
    noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null
): T {
    val factory: ViewModelProvider.Factory? = factoryProducer?.invoke()
    return if (factory == null) {
        ViewModelProvider(context)[T::class.java]
    } else {
        ViewModelProvider(context, factory)[T::class.java]
    }
}


fun readAsStream(fileName: String): InputStream = BaseApplication.context.assets.open(fileName)

fun readAsString(fileName: String): String = readAsStream(fileName).use { inputStream ->
    BufferedReader(InputStreamReader(inputStream, "utf-8")).use {
        val stringBuffer = StringBuffer()
        it.forEachLine {
            stringBuffer.append(it)
        }
        stringBuffer.toString()
    }
}

/****************************************Log打印得扩展函数****************************************************/
fun Any.logd(tag: String = LogUtils.TGA) {
    if (LogUtils.isPrintLog) {
        Log.d(tag, "$this")
    }
}

fun Any.loge(tag: String = LogUtils.TGA) {
    if (LogUtils.isPrintLog) {
        Log.e(tag, "$this")
    }
}

fun Any.logi(tag: String = LogUtils.TGA) {
    if (LogUtils.isPrintLog) {
        Log.i(tag, "$this")
    }
}

fun Any.logv(tag: String = LogUtils.TGA) {
    if (LogUtils.isPrintLog) {
        Log.v(tag, "$this")
    }
}

fun Any.logw(tag: String = LogUtils.TGA) {
    if (LogUtils.isPrintLog) {
        Log.w(tag, "$this")
    }
}

/**
 * 判断传入对象是否为空
 */
fun isNull(any: Any?): Boolean {
    return any?.toString()?.isEmpty() ?: true
}


/**
 * 将任务Json字符串转换为 MutableList<T>列表
 * getJsonToList<ClickBean>(tableClickTask.taskJson)
 */
inline fun <reified T> getJsonToList(jsonString: String?, classData: Class<*>): MutableList<T> =
    Gson().fromJson(jsonString, ParameterizedTypeImpl(classData))


inline fun <reified T> getJsonToObject(jsonString: String): T =
    Gson().fromJson(jsonString, T::class.java)


/**
 * 截取List包括起始结束位置
 */
fun <T> ktsubListInclude(list: MutableList<T>, startIndex: Int, endIndex: Int): MutableList<T> {
    var newList = mutableListOf<T>()
    if (startIndex < 0 || endIndex > list.size) {
        return newList
    }
    for (index in startIndex..endIndex) {
        newList.add(list[index])
    }
    return newList
}

/**
 * 截取List包括起始结束位置
 */
fun <T> ktsubListEnd(list: MutableList<T>, startIndex: Int, endIndex: Int): MutableList<T> {
    var newList = mutableListOf<T>()
    if (startIndex < 0 || endIndex > list.size) {
        return newList
    }
    for (index in startIndex + 1..endIndex) {
        newList.add(list[index])
    }
    return newList
}


val Float.toPx
    get() = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        this,
        Resources.getSystem().displayMetrics
    )
val Int.dp
    get() = this.toFloat().toPx
val Int.sp
    get() = (this * BaseApplication.context.resources.displayMetrics.scaledDensity + 0.5f).toInt()

/**
 * 将ColorID转换为可用的resources
 */
fun Int.toResourcesColor(): Int {
    return BaseApplication.context.resources.getColor(this, null)
}

/**
 * 通过反射初始化ViewBinding
 * 兼容Activity和Fragment
 */
inline fun <VB : ViewBinding> Any.getViewBinding(
    inflater: LayoutInflater,
    container: ViewGroup? = null,
    position: Int = 1
): VB {
    val vbClass =
        (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>()
    val inflate = vbClass[position].getDeclaredMethod(
        "inflate",
        LayoutInflater::class.java,
        ViewGroup::class.java,
        Boolean::class.java
    )
    return inflate.invoke(null, inflater, container, false) as VB
}






